package me.zhengjie.modules.insurance.handler;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.domain.LocalStorage;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.insurance.domain.InsuredUser;
import me.zhengjie.modules.insurance.mapper.InsuredUserMapper;
import me.zhengjie.modules.insurance.service.dto.InsuredUserDto;
import me.zhengjie.modules.system.service.DeptService;
import me.zhengjie.service.LocalStorageService;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 被保用户上传处理器
 *
 * @author HeHui
 * @date 2021-12-27 00:36
 */
@Component
@Slf4j
@AllArgsConstructor
public class InsuredUserUploadHandler {

    private final DeptService deptService;
    private final InsuredUserMapper insuredUserMapper;
    private final LocalStorageService localStorageService;

    /**
     * 上传
     *
     * @param file   文件
     * @param userId 用户id
     */
    public void upload(MultipartFile file, long userId) throws IOException {
        if (null == file || file.isEmpty()) {
            log.error("[人员管理] upload file batch add user, file is empty");
            return;
        }
        LocalStorage localStorage = localStorageService.create(userId + "-" + "导入人员", file);
        List<InsuredUser> userList = readBuilder(FileUtil.getInputStream(localStorage.getPath()), userId);
        if (CollUtil.isEmpty(userList)) {
            log.error("[人员管理] upload file batch add user, read file content is empty");
            return;
        }
        insuredUserMapper.batchInsert(userList);
    }


    /**
     * 读建设者
     *
     * @param inputStream   文件
     * @param userId 用户id
     * @return {@link List}<{@link InsuredUserDto}>
     * @throws IOException ioexception
     */
    private List<InsuredUser> readBuilder(InputStream inputStream, long userId) throws IOException {
        List<List<Object>> readData = read(inputStream, 1000);
        if (CollUtil.isEmpty(readData)) {
            throw new BadRequestException("文件内容为空");
        }
        if (readData.size() > 1000) {
            throw new BadRequestException("单次导入最多处理1000条");
        }
        List<InsuredUserDto> result = new ArrayList<>(readData.size());
        List<String> userIdCards = new ArrayList<>(readData.size());

        for (int i = 0; i < readData.size(); i++) {
            if (CollUtil.isEmpty(readData.get(i))) {
                continue;
            }
            try {
                InsuredUserDto user = buildData(readData.get(i));
                if (userIdCards.contains(user.getUserIdCard())) {
                    throw new BadRequestException(String.format("第[%s]行身份证号码重复", i + 2));
                }
                userIdCards.add(user.getUserIdCard());
                result.add(user);
            } catch (BadRequestException e) {
                throw new BadRequestException(String.format("第[%s]行,%s", i + 2, e.getMessage()));
            }
        }

        List<String> companyNames = result.stream().map(InsuredUserDto::getOwnerCompanyName).distinct().collect(Collectors.toList());
        Map<String, Long> companyNameMap = deptService.getTopDeptIdInNames(companyNames);
        String notFindResultCompanyName = companyNames.stream().filter(v -> !companyNameMap.containsKey(v)).collect(Collectors.joining(","));
        if (StrUtil.isNotBlank(notFindResultCompanyName)) {
            throw new BadRequestException(notFindResultCompanyName + "; 未找到");
        }
        List<String> insertUserIdCards = result.stream().filter(v -> v.getIsDeleted().equals(0)).map(InsuredUserDto::getUserIdCard).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(insertUserIdCards)) {
            Integer effectPolicy = insuredUserMapper.existsIsEffectPolicy(insertUserIdCards);
            if (effectPolicy != null && effectPolicy > 0) {
                throw new BadRequestException("文件增员中存在骑手已生效的保单");
            }

            Map<String, String> userNameMap = Optional.ofNullable(insuredUserMapper.findUserName(insertUserIdCards)).orElse(Collections.emptyList())
                .stream().collect(Collectors.toMap(InsuredUser::getUserIdCard, InsuredUser::getUserName, (v1, v2) -> v1));

            if (CollUtil.isNotEmpty(userNameMap)) {
                String notEqualsIdCards = result.stream().filter(userNameMap::containsKey).filter(r -> !userNameMap.get(r.getUserIdCard()).equals(r.getUserName())).map(InsuredUserDto::getUserIdCard).collect(Collectors.joining(","));
                if (StrUtil.isNotBlank(notEqualsIdCards)) {
                    throw new BadRequestException("文件增员中存在骑手名称与原名称不一致身份证:[" + notEqualsIdCards + "]");
                }
            }
        }

        List<String> delUserIdCards = result.stream().filter(v -> v.getIsDeleted().equals(1)).map(InsuredUserDto::getUserIdCard).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(delUserIdCards)) {
            log.info("[人员管理] insured user upload batch out, userId:[{}], idCard:[{}]", userId,delUserIdCards);
            insuredUserMapper.batchOutInUserIdCard(delUserIdCards, userId);
        }


        Timestamp now = new Timestamp(System.currentTimeMillis());
        return result.stream().filter(v -> v.getIsDeleted().equals(0)).map(v -> {
            InsuredUser user = new InsuredUser();
            user.setCreateUserId(userId);
            user.setIsDeleted(0);
            user.setCreateTime(now);
            user.setLastUpdateTime(now);
            user.setLastUpdateId(userId);
            user.setOwnerId(userId);
            user.setOwnerCompanyId(companyNameMap.get(v.getOwnerCompanyName()));
            user.setUserName(v.getUserName());
            user.setUserIdCard(v.getUserIdCard());
            user.setUserMobile(v.getUserMobile());
            user.setPolicyStartTime(now);
            user.setPolicyStatus(1);
            return user;
        }).collect(Collectors.toList());

    }


    /**
     * 构建数据
     *
     * @param data 数据
     * @return {@link InsuredUser}
     */
    private InsuredUserDto buildData(List<Object> data) {
        InsuredUserDto user = new InsuredUserDto();

        Object userName = CollUtil.get(data, 0);
        if (userName == null || userName.toString().trim().length() < 1) {
            throw new BadRequestException("骑手名称不能为空");
        }
        String name = userName.toString().trim();
        if (name.length() > 10) {
            throw new BadRequestException("骑手名称不能超过10位");
        }

        Object idCard = CollUtil.get(data, 1);
        if (idCard == null || idCard.toString().trim().length() < 1) {
            throw new BadRequestException(userName + "骑手身份证不能为空");
        }
        String card = idCard.toString().trim();
        if (!IdcardUtil.isValidCard(card)) {
            throw new BadRequestException(userName + "骑手身份证号非法");
        }
        Object company = CollUtil.get(data, 2);
        if (company == null || company.toString().trim().length() < 1) {
            throw new BadRequestException(userName + "所属公司不能为空");
        }

        Object operation = CollUtil.get(data, 3);
        if (operation == null || operation.toString().trim().length() < 1) {
            throw new BadRequestException(userName+ "请选择操作");
        }
        if (!Objects.equals(operation,"增员") && !Objects.equals(operation,"减员")) {
            throw new BadRequestException(userName + "请选择增员或减员");
        }

        user.setUserName(name);
        user.setOwnerCompanyName(company.toString().trim());
        user.setUserIdCard(card);
        user.setUserMobile("");
        user.setIsDeleted(Objects.equals(operation,"减员") ? 1 : 0);
        return user;
    }
    /**
     * 读
     *
     * @param stream 流
     * @return {@link List <List<Object>>}
     */
    private List<List<Object>> read(InputStream stream, int maxRead) {
        //10w行以下读取问题不大，10w以上推荐 EasyExcel
        return ExcelUtil.getReader(stream).read(1,maxRead);
    }
}
